﻿/*********************************************************************************
**                                                                              **
**  Copyright (C) 2024 LiLong                                                   **
**  This file is part of GnssLogs.                                              **
**                                                                              **
**  GnssLogs is free software: you can redistribute it and/or modify            **
**  it under the terms of the GNU Lesser General Public License as published by **
**  the Free Software Foundation, either version 3 of the License, or           **
**  (at your option) any later version.                                         **
**                                                                              **
**  GnssLogs is distributed in the hope that it will be useful,                 **
**  but WITHOUT ANY WARRANTY; without even the implied warranty of              **
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               **
**  GNU Lesser General Public License for more details.                         **
**                                                                              **
**  You should have received a copy of the GNU Lesser General Public License    **
**  along with GnssLogs.  If not, see <https://www.gnu.org/licenses/>.          **
**********************************************************************************/
#pragma once

#include "../ALMANAC.h"
#include "LogHeaderDecoder.h"

namespace GnssLogs
{
namespace ALMANACDecoder
{
using Sync   = TAO_PEGTL_STRING("#ALMANACA");
using Header = LogHeaderDecoder::SyncExpression<Sync>;
// clang-format off
struct Messages : star<digit> {};
struct PRN : star<digit> {};
struct Week : star<digit> {};
struct Seconds : Floating {};
struct ECC : Floating {};
struct RateOfRightAscension : Floating {};
struct RightAscension : Floating {};
struct ArgumentOfPerigee : Floating {};
struct Mo : Floating {};
struct AF0 : Floating {};
struct AF1 : Floating {};
struct N0 : Floating {};
struct A : Floating {};
struct InclAngle : Floating {};
struct SVConfig : star<digit> {};
struct HealthPRN : star<digit> {};
struct HealthAlm : star<digit> {};
struct Antispoof : sor<TAO_PEGTL_STRING("TRUE"), TAO_PEGTL_STRING("FALSE")> {};
// clang-format on
using Prns = seq<Split,
                 PRN,
                 Split,
                 Week,
                 Split,
                 Seconds,
                 Split,
                 ECC,
                 Split,
                 RateOfRightAscension,
                 Split,
                 RightAscension,
                 Split,
                 ArgumentOfPerigee,
                 Split,
                 Mo,
                 Split,
                 AF0,
                 Split,
                 AF1,
                 Split,
                 N0,
                 Split,
                 A,
                 Split,
                 InclAngle,
                 Split,
                 SVConfig,
                 Split,
                 HealthPRN,
                 Split,
                 HealthAlm,
                 Split,
                 Antispoof>;

using Expression = seq<Header, Messages, star<Prns>, one<'*'>, CRC32, Tail>;
template<typename T>
struct Action
{
};

template<>
struct Action<Header> : LogHeaderDecoder::LogHeaderHelperNoSetValue
{
};

template<>
struct Action<Messages> : IntHelper<Action<Messages>, uint32_t>
{
    static void setValue(ALMANAC::Data& data, uint32_t value) { data.messages = value; }
};

template<>
struct Action<PRN> : IntHelper<Action<PRN>, uint32_t>
{
    static void setValue(ALMANAC::Data& data, uint32_t value)
    {
        data.prns.push_back(ALMANAC::Data::Prn {});
        data.prns.back().prn = value;
    }
};

template<>
struct Action<Week> : IntHelper<Action<Week>, uint32_t>
{
    static void setValue(ALMANAC::Data& data, uint32_t value) { data.prns.back().week = value; }
};

template<>
struct Action<Seconds> : DoubleHelper<Action<Seconds>>
{
    static void setValue(ALMANAC::Data& data, double value) { data.prns.back().seconds = value; }
};

template<>
struct Action<ECC> : DoubleHelper<Action<ECC>>
{
    static void setValue(ALMANAC::Data& data, double value) { data.prns.back().ecc = value; }
};

template<>
struct Action<RateOfRightAscension> : DoubleHelper<Action<RateOfRightAscension>>
{
    static void setValue(ALMANAC::Data& data, double value) { data.prns.back().rateOfRightAscension = value; }
};

template<>
struct Action<RightAscension> : DoubleHelper<Action<RightAscension>>
{
    static void setValue(ALMANAC::Data& data, double value) { data.prns.back().rightAscension = value; }
};

template<>
struct Action<ArgumentOfPerigee> : DoubleHelper<Action<ArgumentOfPerigee>>
{
    static void setValue(ALMANAC::Data& data, double value) { data.prns.back().argumentOfPerigee = value; }
};

template<>
struct Action<Mo> : DoubleHelper<Action<Mo>>
{
    static void setValue(ALMANAC::Data& data, double value) { data.prns.back().mo = value; }
};

template<>
struct Action<AF0> : DoubleHelper<Action<AF0>>
{
    static void setValue(ALMANAC::Data& data, double value) { data.prns.back().af0 = value; }
};

template<>
struct Action<AF1> : DoubleHelper<Action<AF1>>
{
    static void setValue(ALMANAC::Data& data, double value) { data.prns.back().af1 = value; }
};

template<>
struct Action<N0> : DoubleHelper<Action<N0>>
{
    static void setValue(ALMANAC::Data& data, double value) { data.prns.back().n0 = value; }
};

template<>
struct Action<A> : DoubleHelper<Action<A>>
{
    static void setValue(ALMANAC::Data& data, double value) { data.prns.back().a = value; }
};

template<>
struct Action<InclAngle> : DoubleHelper<Action<InclAngle>>
{
    static void setValue(ALMANAC::Data& data, double value) { data.prns.back().inclAngle = value; }
};

template<>
struct Action<SVConfig> : IntHelper<Action<SVConfig>, uint32_t>
{
    static void setValue(ALMANAC::Data& data, uint32_t value) { data.prns.back().svConfig = value; }
};

template<>
struct Action<HealthPRN> : IntHelper<Action<HealthPRN>, uint32_t>
{
    static void setValue(ALMANAC::Data& data, uint32_t value) { data.prns.back().healthPrn = value; }
};

template<>
struct Action<HealthAlm> : IntHelper<Action<HealthAlm>, uint32_t>
{
    static void setValue(ALMANAC::Data& data, uint32_t value) { data.prns.back().healthAlm = value; }
};

template<>
struct Action<Antispoof>
{
    template<typename ParseInput>
    static bool apply(ParseInput& in, ALMANAC::Data& data)
    {
        data.prns.back().antispoof = std::string(in.begin(), in.size()) == "TRUE";
        return true;
    }
};

template<>
struct Action<CRC32> : CRC32Helper<Action<CRC32>>
{
    static void setValue(ALMANAC::Data& data, uint32_t value) { data.crc32 = value; }
};
} // namespace ALMANACDecoder
} // namespace GnssLogs